package org.nf.web.servlet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * @author wangl
 * @date 2024/5/22
 * 拦截器链
 */
public class HandlerExecutionChain {
    private final Logger log = LoggerFactory.getLogger(getClass());
    /**
     * 请求处理对象
     */
    private final Object handler;

    /**
     * 拦截器链
     */
    private final List<HandlerInterceptor> interceptorList = new ArrayList<>();

    /**
     * 拦截器执行的下标
     */
    private Integer interceptorIndex = -1;

    public HandlerExecutionChain(Object handler) {
        this.handler = handler;
    }

    public Object getHandler() {
        return handler;
    }

    public void addInterceptor(HandlerInterceptor interceptor) {
        interceptorList.add(interceptor);
    }

    public List<HandlerInterceptor> getInterceptorList() {
        return interceptorList;
    }

    /**
     * 执行拦截器的preHandle
     */
    boolean applyPreHandle(ServletApi api) throws Exception {
        for (int i = 0; i < this.interceptorList.size(); i++) {
            HandlerInterceptor interceptor = this.interceptorList.get(i);
            if (!interceptor.preHandle(api.request(), api.response(), this.handler)) {
                triggerAfterCompletion(api, null);
                return false;
            }
            this.interceptorIndex = i;
        }
        return true;
    }

    /**
     * 执行拦截器的postHandle
     */
    void applyPostHandle(ServletApi api, BaseView view)
            throws Exception {
        for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = this.interceptorList.get(i);
            interceptor.postHandle(api.request(), api.response(), this.handler, view);
        }
    }

    /**
     * 执行拦截器的afterCompletion
     */
    void triggerAfterCompletion(ServletApi api, Throwable e) {
        for (int i = this.interceptorIndex; i >= 0; i--) {
            HandlerInterceptor interceptor = this.interceptorList.get(i);
            try {
                interceptor.afterCompletion(api.request(), api.response(), this.handler, e);
            }
            catch (Throwable t) {
                log.error("HandlerInterceptor.afterCompletion threw exception", t);
            }
        }
    }
}